<!DOCTYPE html><html class="theme-next pisces use-motion" lang="zh-Hans"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="theme-color" content="#222"><meta name="baidu-site-verification" content="YdMoGbLGAx"><script src="/lib/pace/pace.min.js?v=1.0.2"></script><link href="/lib/pace/pace-theme-minimal.min.css?v=1.0.2" rel="stylesheet"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><meta name="google-site-verification" content="L2XxDS_YgUmo9ng6ga0rnR1w_IcqBAut-k_te_C1TCQ"><link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"><link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css"><link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css"><link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico?v=5.1.4"><link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico?v=5.1.4"><meta name="keywords" content="Java, Spring, Spring boot, Machine learning, Deep learning"><meta name="description" content="Spring通过这种控制反转（IOC）的设计模式促进了松耦合，这种方式使一个对象依赖其它对象时会通过被动的方式传送进来，而不是通过手动创建这些类。"><meta property="og:type" content="article"><meta property="og:title" content="Spring IOC 原理概述"><meta property="og:url" content="http://gtwlover.gitee.io/2017/02/25/Spring IOC/index.html"><meta property="og:site_name" content="Better Man"><meta property="og:description" content="Spring通过这种控制反转（IOC）的设计模式促进了松耦合，这种方式使一个对象依赖其它对象时会通过被动的方式传送进来，而不是通过手动创建这些类。"><meta property="og:image" content="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/%E9%A1%B9%E7%9B%AE/%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A81.png"><meta property="og:image" content="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/%E9%A1%B9%E7%9B%AE/%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A82.png"><meta property="og:updated_time" content="2018-02-12T12:34:09.000Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Spring IOC 原理概述"><meta name="twitter:description" content="Spring通过这种控制反转（IOC）的设计模式促进了松耦合，这种方式使一个对象依赖其它对象时会通过被动的方式传送进来，而不是通过手动创建这些类。"><meta name="twitter:image" content="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/%E9%A1%B9%E7%9B%AE/%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A81.png"><script type="text/javascript" id="hexo.configurations">var NexT=window.NexT||{},CONFIG={root:"/",scheme:"Pisces",version:"5.1.4",sidebar:{position:"left",display:"post",offset:12,b2t:!1,scrollpercent:!0,onmobile:!1},fancybox:!0,tabs:!0,motion:{enable:!0,async:!1,transition:{post_block:"fadeIn",post_header:"slideDownIn",post_body:"slideDownIn",coll_header:"slideLeftIn",sidebar:"slideUpIn"}},duoshuo:{userId:"gtwlover",author:"博主"},algolia:{applicationID:"GOSX1252HP",apiKey:"eefb124f52fc415c356384bb0ed50bda",indexName:"myblog",hits:{per_page:10},labels:{input_placeholder:"请输入要查找的关键字",hits_empty:"未找到 ${query} 相关结果",hits_stats:"${hits} 条相关条目，使用了 ${time} 毫秒"}}}</script><link rel="canonical" href="http://gtwlover.gitee.io/2017/02/25/Spring IOC/"><title>Spring IOC 原理概述 | Better Man</title><script>!function(e,a,t,n,g,c,o){e.GoogleAnalyticsObject=g,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,c=a.createElement(t),o=a.getElementsByTagName(t)[0],c.async=1,c.src="https://www.google-analytics.com/analytics.js",o.parentNode.insertBefore(c,o)}(window,document,"script",0,"ga"),ga("create","UA-97111795-1","auto"),ga("send","pageview")</script></head><body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans"><div class="container sidebar-position-left page-post-detail"><div class="headband"></div> <a href="https://github.com/gaotingwang"><img style="position:absolute;top:0;right:0;border:0" src="https://camo.githubusercontent.com/652c5b9acfaddf3a9c326fa6bde407b87f7be0f4/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6f72616e67655f6666373630302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png"></a><header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="header-inner"><div class="site-brand-wrapper"><div class="site-meta"><div class="custom-logo-site-title"><a href="/" class="brand" rel="start"><span class="logo-line-before"><i></i></span> <span class="site-title">Better Man</span><span class="logo-line-after"><i></i></span></a></div><p class="site-subtitle">时间以北慕城南，故人以北爱荒凉</p></div><div class="site-nav-toggle"> <button><span class="btn-bar"></span><span class="btn-bar"></span><span class="btn-bar"></span></button></div></div><nav class="site-nav"><ul id="menu" class="menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="menu-item-icon fa fa-fw fa-home"></i><br> 首页</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i><br> 归档</a></li><li class="menu-item menu-item-search"><a href="javascript:;" class="popup-trigger"><i class="menu-item-icon fa fa-search fa-fw"></i><br> 搜索</a></li></ul><div class="site-search"><div class="algolia-popup popup search-popup"><div class="algolia-search"><div class="algolia-search-input-icon"><i class="fa fa-search"></i></div><div class="algolia-search-input" id="algolia-search-input"></div></div><div class="algolia-results"><div id="algolia-stats"></div><div id="algolia-hits"></div><div id="algolia-pagination" class="algolia-pagination"></div></div><span class="popup-btn-close"><i class="fa fa-times-circle"></i></span></div></div></nav></div></header><main id="main" class="main"><div class="main-inner"><div class="content-wrap"><div id="content" class="content"><div id="posts" class="posts-expand"><article class="post post-type-normal" itemscope itemtype="http://schema.org/Article"><div class="post-block"><link itemprop="mainEntityOfPage" href="http://gtwlover.gitee.io/2017/02/25/Spring IOC/"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="脱毛大白兔"><meta itemprop="description" content=""><meta itemprop="image" content="http://gtw.oss-cn-shanghai.aliyuncs.com/myself/my3.jpeg?x-oss-process=style/zoom"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Better Man"></span><header class="post-header"><h1 class="post-title" itemprop="name headline">Spring IOC 原理概述</h1><div class="post-meta"><span class="post-time"><span class="post-meta-item-icon"><i class="fa fa-calendar-o"></i></span> <span class="post-meta-item-text">发表于</span> <time title="创建于" itemprop="dateCreated datePublished" datetime="2017-02-25T21:01:21+08:00">2017-02-25</time></span> <span class="post-category"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-folder-o"></i></span> <span class="post-meta-item-text">分类于</span> <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/Spring/" itemprop="url" rel="index"><span itemprop="name">Spring</span></a></span></span> <span class="post-comments-count"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-comment-o"></i></span><a href="/2017/02/25/Spring IOC/#comments" itemprop="discussionUrl"><span class="post-comments-count gitment-comments-count" data-xid="/2017/02/25/Spring IOC/" itemprop="commentsCount"></span></a></span> <span id="/2017/02/25/Spring IOC/" class="leancloud_visitors" data-flag-title="Spring IOC 原理概述"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-eye"></i></span> <span class="post-meta-item-text">阅读次数&#58;</span><span class="leancloud-visitors-count"></span></span><div class="post-description"> Spring通过这种控制反转（IOC）的设计模式促进了松耦合，这种方式使一个对象依赖其它对象时会通过被动的方式传送进来，而不是通过手动创建这些类。</div></div></header><div class="post-body" itemprop="articleBody"><h1 id="Spring-IOC-的原理概述"><a href="#Spring-IOC-的原理概述" class="headerlink" title="Spring IOC 的原理概述"></a>Spring IOC 的原理概述</h1><p>在我们的日常开发中，创建对象的操作随处可见以至于对其十分熟悉的同时又感觉十分繁琐，每次需要对象都需要亲手将其new出来，甚至某些情况下由于坏编程习惯还会造成对象无法被回收，这是相当糟糕的。但更为严重的是，我们一直倡导的松耦合，少入侵原则，这种情况下变得一无是处。于是前辈们开始谋求改变这种编程陋习，考虑如何使用编码更加解耦合，由此而来的解决方案是面向接口的编程，于是便有了如下写法：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BookServiceImpl</span> </span>&#123;</div><div class="line">    <span class="comment">//class</span></div><div class="line">    <span class="keyword">private</span>  BookDaoImpl bookDaoImpl;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">oldCode</span><span class="params">()</span></span>&#123;</div><div class="line">        <span class="comment">//原来的做法</span></div><div class="line">        bookDaoImpl=<span class="keyword">new</span> bookDaoImpl();</div><div class="line">        bookDaoImpl.getAllCategories();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">//=================new====================</span></div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BookServiceImpl</span> </span>&#123;</div><div class="line">    <span class="comment">//interface</span></div><div class="line">    <span class="keyword">private</span> BookDao bookDao;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">newCode</span><span class="params">()</span></span>&#123;</div><div class="line">        <span class="comment">//变为面向接口编程</span></div><div class="line">        bookDao=<span class="keyword">new</span> bookDaoImpl();</div><div class="line">        bookDao.getAllCategories();</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>BookServiceImpl类中由原来直接与BookDaoImp打交互变为BookDao，即使BookDao最终实现依然是BookDaoImp，这样的做的好处是显而易见的，所有调用都通过接口bookDao来完成，而接口的真正的实现者和最终的执行者就是bookDaoImpl，当替换bookDaoImpl类，也只需修改bookDao指向新的实现类。</p><p><img src="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/%E9%A1%B9%E7%9B%AE/%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A81.png" alt="img"></p><p>虽然上述的代码在很大程度上降低了代码的耦合度，但是代码依旧存在入侵性和一定程度的耦合性，比如在修改bookDao的实现类时，仍然需求修改BookServiceImpl的内部代码，当依赖的类多起来时，查找和修改的过程也会显得相当糟糕，因此我们仍需要寻找一种方式，它可以令开发者在无需触及BookServiceImpl内容代码的情况下实现修改bookDao的实现类，以便达到最低的耦合度和最少入侵的目的。</p><p>实际上存在一种称为反射的编程技术可以协助解决上述问题，反射是一种根据给出的完整类名（字符串方式）来动态地生成对象，这种编程方式可以让对象在生成时才决定到底是哪一种对象，因此可以这样假设，在某个配置文件，该文件已写好bookDaoImpl类的完全限定名称，通过读取该文件而获取到bookDao的真正实现类完全限定名称，然后通过反射技术在运行时动态生成该类，最终赋值给bookDao接口，也就解决了刚才的存在问题，这里为简单演示，使用properties文件作为配置文件，className.properties如下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">bookDao.name=com.gtw.spring.dao.BookDaoImpl1</div></pre></td></tr></table></figure><p>获取该配置文件信息动态为bookDao生成实现类：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title">BookService</span></span>&#123;</div><div class="line">    <span class="comment">//读取配置文件的工具类</span></div><div class="line">    PropertiesUtil propertiesUtil=<span class="keyword">new</span> PropertiesUtil(<span class="string">"conf/className.properties"</span>);</div><div class="line"></div><div class="line">    <span class="keyword">private</span> BookDao bookDao;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">DaymicObject</span><span class="params">()</span> <span class="keyword">throws</span> ClassNotFoundException, IllegalAccessException, InstantiationException </span>&#123;</div><div class="line">        <span class="comment">//获取完全限定名称</span></div><div class="line">        String className=propertiesUtil.get(<span class="string">"bookDao.name"</span>);<span class="comment">// 此处还是有代码侵入</span></div><div class="line">        <span class="comment">//通过反射</span></div><div class="line">        Class c=Class.forName(className);</div><div class="line">        <span class="comment">//动态生成实例对象</span></div><div class="line">        bookDao= (BookDao) c.newInstance();</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>的确如我们所愿生成了bookDao的实例，这样做的好处是在替换bookDao实现类的情况只需修改配置文件的内容而无需触及BookServiceImpl的内部代码，从而把代码修改的过程转到配置文件中，相当于BookServiceImpl及其内部的bookDao通过配置文件与bookDao的实现类进行关联，这样BookServiceImpl与bookDao的实现类间也就实现了解耦合，当然BookServiceImpl类中存在着BookDao对象是无法避免的，毕竟这是协同工作的基础，我们只能最大程度去解耦合。</p><p><img src="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/%E9%A1%B9%E7%9B%AE/%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A82.png" alt="img"></p><p>了解了上述的问题再来理解IOC就显得简单多了。Spring IOC 也是一个java对象，在某些特定的时间被创建后，可以进行对其他对象的控制，包括初始化、创建、销毁等。简单地理解，在上述过程中，我们通过配置文件配置了BookDaoImpl实现类的完全限定名称，然后利用反射在运行时为BookDao创建实际实现类，包括BookServiceImpl的创建，Spring的IOC容器都会帮我们完成，而我们唯一要做的就是把需要创建的类和其他类依赖的类以配置文件的方式告诉IOC容器需要创建那些类和注入哪些类即可。</p><p>Spring通过这种控制反转（IOC）的设计模式促进了松耦合，这种方式使一个对象依赖其它对象时会通过被动的方式传送进来（如BookServiceImpl被创建时，其依赖的BookDao的实现类也会同时被注入BookServiceImpl中），而不是通过手动创建这些类。我们可以把IOC模式看做是工厂模式的升华，可以把IOC看作是一个大工厂，只不过这个大工厂里要生成的对象都是在配置文件(XML)中给出定义的，然后利用Java的反射技术，根据XML中给出的类名生成相应的对象。</p><p>从某种程度上来说，IOC相当于把在工厂方法里通过硬编码创建对象的代码，改变为由XML文件来定义，也就是把工厂和对象生成这两者独立分隔开来，目的就是提高灵活性和可维护性，更是达到最低的耦合度，因此我们要明白所谓为的IOC就将对象的创建权,交由Spring完成，从此解放手动创建对象的过程，同时让类与类间的关系到达最低耦合度。</p><h1 id="Spring-容器装配Bean（XML配置方式和注解配置方式）"><a href="#Spring-容器装配Bean（XML配置方式和注解配置方式）" class="headerlink" title="Spring 容器装配Bean（XML配置方式和注解配置方式）"></a>Spring 容器装配Bean（XML配置方式和注解配置方式）</h1><p>我们采用xml配置文件的方式对bean进行声明和管理，每一个bean标签都代表着需要被创建的对象并通过property标签可以为该类注入其他依赖对象（关于依赖后面会分析，这里简单理解为将对象实例传入到某个bean实例即可），通过这种方式Spring容器就可以成功知道我们需要创建那些bean实例，如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></div><div class="line">       <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></div><div class="line">       <span class="attr">xsi:schemaLocation</span>=<span class="string">"</span></div><div class="line">        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</div><div class="line">        "&gt;</div><div class="line">    <span class="comment">&lt;!-- 声明accountDao对象,交给spring创建 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</span></div><div class="line">    <span class="comment">&lt;!-- 声明accountService对象,交给spring创建 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountService"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.AccountServiceImpl"</span>&gt;</span></div><div class="line">          <span class="comment">&lt;!-- 注入accountDao对象,需要set方法--&gt;</span></div><div class="line">          <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">ref</span>=<span class="string">"accountDao"</span>/&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></div></pre></td></tr></table></figure><p>然后通过<code>ClassPathXmlApplicationContext</code>去加载spring的配置文件，接着获取想要的实例bean并调用相应方法执行。对于<code>ClassPathXmlApplicationContext</code>默认加载<code>classpath</code>路径下的文件，只需指明对应文件的<code>classpath</code>路径即可。如果存在多个配置文件，则只需分别传递即可，<code>ClassPathXmlApplicationContext</code>是一个可以接收可变参数的构造函数。实际上<code>ClassPathXmlApplicationContext</code>还有一个孪生兄弟<code>FileSystemXmlApplicationContext</code>，它默认为项目工作路径即项目的根目录 ，至于使用哪个，觉得没多大的差别。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//默认查找classpath路径下的文件</span></div><div class="line">ApplicationContext applicationContext=<span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="string">"spring/spring-ioc.xml"</span>);</div><div class="line"><span class="comment">//多文件,也可传递数组</span></div><div class="line">ApplicationContext applicationContext=<span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="string">"spring/spring-ioc.xml"</span>,<span class="string">"spring/spring-ioc2.xml"</span>,.....);</div><div class="line"></div><div class="line"><span class="comment">//默认为项目工作路径 即项目的根目录 </span></div><div class="line">FileSystemXmlApplicationContext applicationContext=</div><div class="line">                <span class="keyword">new</span> FileSystemXmlApplicationContext(<span class="string">"/src/main/resources/spring/spring-ioc.xml"</span>);</div><div class="line"></div><div class="line"><span class="comment">//也可以读取classpath下的文件</span></div><div class="line">FileSystemXmlApplicationContext applicationContext=<span class="keyword">new</span> FileSystemXmlApplicationContext(<span class="string">"classpath:spring/spring-ioc.xml"</span>);</div><div class="line"></div><div class="line"><span class="comment">//使用前缀file 表示的是文件的绝对路径 </span></div><div class="line">ApplicationContext applicationContext = <span class="keyword">new</span> FileSystemXmlApplicationContext(<span class="string">"file:D:/app.spring.xml"</span>); </div><div class="line"><span class="comment">//多文件与ClassPathXmlApplicationContext相同</span></div></pre></td></tr></table></figure><p>ok~，了解完如何加载配置文件后，下面将采用注解的方式来达到上述xml的配置的效果：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Configuration</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BeanConfiguration</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="meta">@Bean</span></div><div class="line">    <span class="function"><span class="keyword">public</span> AccountDao <span class="title">accountDao</span><span class="params">()</span></span>&#123;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">new</span> AccountDaoImpl();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Bean</span></div><div class="line">    <span class="function"><span class="keyword">public</span> AccountService <span class="title">accountService</span><span class="params">()</span></span>&#123;</div><div class="line">        AccountServiceImpl bean=<span class="keyword">new</span> AccountServiceImpl();</div><div class="line">        <span class="comment">//注入dao</span></div><div class="line">        bean.setAccountDao(accountDao());</div><div class="line">        <span class="keyword">return</span> bean;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>上述代码中使用了@Configuration注解标明BeanConfiguration类，使得BeanConfiguration类替代了xml文件，也就是说注解@Configuration等价于＜beans＞标签。在该类中，每个使用注解@Bean的公共方法对应着一个＜bean＞标签的定义，即@Bean等价于＜bean＞标签。这种基于java的注解配置方式是在spring3.0中引入的，此时使用到注解，因此必须确保spring-context包已引入。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-context<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;spring.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></div></pre></td></tr></table></figure><p>那怎么使用呢？事实上跟xml很相似，不过这是使用到<code>AnnotationConfigApplicationContext</code>来加载java的配置文件，运行结果跟xml一样。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Test</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testByConfigurationAnnotation</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line"></div><div class="line">    AnnotationConfigApplicationContext config=<span class="keyword">new</span> AnnotationConfigApplicationContext(BeanConfiguration.class);</div><div class="line"></div><div class="line">    <span class="comment">//名称必须BeanConfiguration中工程方法名称一致</span></div><div class="line">    AccountService accountService= (AccountService) config.getBean(<span class="string">"accountService"</span>);</div><div class="line">    accountService.doSomething();</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure><p>这里我们需要明白的是，在大部分情况下更倾向于使用xml来配置Bean的相关信息，这样会更加方便我们对代码进行管理，因此后面的分析都会基于xml的配置，除了前面通过在xml中使用＜bean＞标签为每个类声明实例外，Spring容器还为我们提供了基于注解的声明方式，这点放在后面分析，接着再来解Spring提供的依赖注入功能。</p><h1 id="Spring-依赖注入"><a href="#Spring-依赖注入" class="headerlink" title="Spring 依赖注入"></a>Spring 依赖注入</h1><p>所谓的依赖注入，其实是当一个bean实例引用到了另外一个bean实例时spring容器帮助我们创建依赖bean实例并注入（传递）到另一个bean中，如上述案例中的AccountService依赖于AccountDao，Spring容器会在创建AccountService的实现类和AccountDao的实现类后，把AccountDao的实现类注入AccountService实例中，下面分别介绍setter注入和构造函数注入。</p><h2 id="Setter注入"><a href="#Setter注入" class="headerlink" title="Setter注入"></a>Setter注入</h2><p>Setter注入顾名思义，被注入的属性需要有set方法， Setter注入支持简单类型和引用类型，Setter注入时在bean实例创建完成后执行的。直接观察前面的案例，对象注入使用＜property＞的ref属性。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!-- 声明accountDao对象并交给spring创建 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</span></div><div class="line"><span class="comment">&lt;!-- 声明accountService对象,交给spring创建 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountService"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.AccountServiceImpl"</span>&gt;</span></div><div class="line">      <span class="comment">&lt;!-- 通过setter注入accountDao对象,对象注入使用ref--&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">ref</span>=<span class="string">"accountDao"</span>/&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div></pre></td></tr></table></figure><p>除了上述的对象注入同时也可以注入简单值和map、set、list、数组，简单值注入使用＜property＞的value属性：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Account</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> String name;</div><div class="line">    <span class="keyword">private</span> String pwd;</div><div class="line">    <span class="keyword">private</span> List&lt;String&gt; citys;</div><div class="line">    <span class="keyword">private</span> Set&lt;String&gt; friends;</div><div class="line">    <span class="keyword">private</span> Map&lt;Integer,String&gt; books;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.name = name;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPwd</span><span class="params">(String pwd)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.pwd = pwd;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCitys</span><span class="params">(List&lt;String&gt; citys)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.citys = citys;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setFriends</span><span class="params">(Set&lt;String&gt; friends)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.friends = friends;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setBooks</span><span class="params">(Map&lt;Integer, String&gt; books)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.books = books;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>注入代码如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!-- setter通过property 注入属性值，普通类型使用value --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"account"</span> <span class="attr">scope</span>=<span class="string">"prototype"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.pojo.Account"</span> &gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"name"</span> <span class="attr">value</span>=<span class="string">"I am SpringIOC1"</span> /&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"pwd"</span> <span class="attr">value</span>=<span class="string">"123"</span> /&gt;</span></div><div class="line">    <span class="comment">&lt;!-- 注入map --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"books"</span>&gt;</span>  </div><div class="line">        <span class="tag">&lt;<span class="name">map</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">"10"</span> <span class="attr">value</span>=<span class="string">"CoreJava"</span>&gt;</span>  </div><div class="line">            <span class="tag">&lt;/<span class="name">entry</span>&gt;</span>  </div><div class="line">            <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">"11"</span> <span class="attr">value</span>=<span class="string">"JavaWeb"</span>&gt;</span>  </div><div class="line">            <span class="tag">&lt;/<span class="name">entry</span>&gt;</span>  </div><div class="line">            <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">"12"</span> <span class="attr">value</span>=<span class="string">"SSH2"</span>&gt;</span>  </div><div class="line">            <span class="tag">&lt;/<span class="name">entry</span>&gt;</span>  </div><div class="line">        <span class="tag">&lt;/<span class="name">map</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;/<span class="name">property</span>&gt;</span>  </div><div class="line">  <span class="comment">&lt;!-- 注入set --&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"friends"</span>&gt;</span>  </div><div class="line">       <span class="tag">&lt;<span class="name">set</span>&gt;</span>  </div><div class="line">           <span class="tag">&lt;<span class="name">value</span>&gt;</span>张龙<span class="tag">&lt;/<span class="name">value</span>&gt;</span>  </div><div class="line">           <span class="tag">&lt;<span class="name">value</span>&gt;</span>老王<span class="tag">&lt;/<span class="name">value</span>&gt;</span>  </div><div class="line">           <span class="tag">&lt;<span class="name">value</span>&gt;</span>王五<span class="tag">&lt;/<span class="name">value</span>&gt;</span>  </div><div class="line">       <span class="tag">&lt;/<span class="name">set</span>&gt;</span>  </div><div class="line">   <span class="tag">&lt;/<span class="name">property</span>&gt;</span>  </div><div class="line">  <span class="comment">&lt;!-- 注入list --&gt;</span></div><div class="line">   <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"citys"</span>&gt;</span>  </div><div class="line">       <span class="tag">&lt;<span class="name">list</span>&gt;</span>  </div><div class="line">           <span class="tag">&lt;<span class="name">value</span>&gt;</span>北京<span class="tag">&lt;/<span class="name">value</span>&gt;</span>  </div><div class="line">           <span class="tag">&lt;<span class="name">value</span>&gt;</span>上海<span class="tag">&lt;/<span class="name">value</span>&gt;</span>  </div><div class="line">           <span class="tag">&lt;<span class="name">value</span>&gt;</span>深圳<span class="tag">&lt;/<span class="name">value</span>&gt;</span></div><div class="line">           <span class="tag">&lt;<span class="name">value</span>&gt;</span>广州<span class="tag">&lt;/<span class="name">value</span>&gt;</span>  </div><div class="line">       <span class="tag">&lt;/<span class="name">list</span>&gt;</span>  </div><div class="line">   <span class="tag">&lt;/<span class="name">property</span>&gt;</span>  </div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div></pre></td></tr></table></figure><h2 id="构造函数注入"><a href="#构造函数注入" class="headerlink" title="构造函数注入"></a>构造函数注入</h2><p>构造注入也就是通过构造方法注入依赖，构造函数的参数一般情况下就是依赖项，spring容器会根据bean中指定的构造函数参数来决定调用那个构造函数，同样看一个案例：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AccountServiceImpl</span> <span class="keyword">implements</span> <span class="title">AccountService</span></span>&#123;</div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 需要注入的对象Dao层对象</div><div class="line">     */</div><div class="line">    <span class="keyword">private</span> AccountDao accountDao;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 构造注入</div><div class="line">     * <span class="doctag">@param</span> accountDao</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AccountServiceImpl</span><span class="params">(AccountDao accountDao)</span></span>&#123;</div><div class="line">        <span class="keyword">this</span>.accountDao=accountDao;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">//........</span></div><div class="line">&#125;</div></pre></td></tr></table></figure><p>xml配置如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</span></div><div class="line"><span class="comment">&lt;!-- 通过构造注入依赖 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountService"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.AccountServiceImpl"</span>&gt;</span></div><div class="line">    <span class="comment">&lt;!-- 构造方法方式注入accountDao对象,--&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span>  <span class="attr">ref</span>=<span class="string">"accountDao"</span>/&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div></pre></td></tr></table></figure><p>当然跟setter注入一样，构造注入也可传入简单值类型和集合类型，这个比较简单，不啰嗦。需要注意的是，当一个bean定义中有多个＜constructor-arg＞标签时，它们的放置顺序并不重要，因为Spring容器会通过传入的依赖参数与类中的构造函数的参数进行比较，尝试找到合适的构造函数。可惜的是，在某些情况下可能会出现问题，如下的User类，带有两个构造函数，参数类型和个数都是一样的，只是顺序不同，这在class的定义中是允许的，但对于Spring容器来说却是一种灾难。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String name;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> age;</div><div class="line"></div><div class="line">    <span class="comment">//第一个构造函数</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">User</span><span class="params">(String name , <span class="keyword">int</span> age)</span></span>&#123;</div><div class="line">        <span class="keyword">this</span>.name=name;</div><div class="line">        <span class="keyword">this</span>.age=age;</div><div class="line">    &#125;</div><div class="line">    <span class="comment">//第二个构造函数</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">User</span><span class="params">(<span class="keyword">int</span> age,String name)</span></span>&#123;</div><div class="line">        <span class="keyword">this</span>.name=name;</div><div class="line">        <span class="keyword">this</span>.age=age;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>配置信息：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"user"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.pojo.User"</span> &gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span>  <span class="attr">type</span>=<span class="string">"java.lang.String"</span> <span class="attr">value</span>=<span class="string">"Jack"</span>/&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span>  <span class="attr">type</span>=<span class="string">"int"</span> <span class="attr">value</span>=<span class="string">"26"</span>/&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div></pre></td></tr></table></figure><p>当程序运行时，Spring容器会尝试查找适合的User构造函数进而创建User对象，由于＜constructor-arg＞的注入顺序并不重要，从而导致不知该使用两种构造函数中的那种，这时user实例将创建失败，Spring容器也将启动失败。幸运地是，Spring早已为我们预测到这种情况，因此只要给Spring容器一点点提示，它便能成功找到适合的构造函数从而创建user实例，在＜constructor-arg＞标签中存在一个index的属性，通过index属性可以告诉spring容器传递的依赖参数的顺序，下面的配置将会令Spring容器成功找到第一个构造函数并调用创建user实例。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"user"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.pojo.User"</span> &gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">index</span>=<span class="string">"0"</span> <span class="attr">value</span>=<span class="string">"Jack"</span>/&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">index</span>=<span class="string">"1"</span> <span class="attr">value</span>=<span class="string">"26"</span>/&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div></pre></td></tr></table></figure><p>在日常的开发中，setter注入和构造注入经常会混合使用，这并不用感觉到诧异，后面我们还会分析到注解装配，它在开发中将更为常用。</p><h2 id="循环依赖"><a href="#循环依赖" class="headerlink" title="循环依赖"></a>循环依赖</h2><p>除了上述的现象，在构造函数注入还有一个无法解决的循环依赖的问题，如下有两个bean，A和B，这两个bean通过构造函数互为依赖，这种情况下Spring容器将无法实例化这两个bean。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">A</span></span>&#123;</div><div class="line">    <span class="keyword">private</span> B b;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">A</span><span class="params">(B b)</span></span>&#123;</div><div class="line">     <span class="keyword">this</span>.b=b;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">B</span></span>&#123;</div><div class="line">    <span class="keyword">private</span> A a;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">B</span><span class="params">(A a)</span></span>&#123;</div><div class="line">     <span class="keyword">this</span>.a=a;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"a"</span> <span class="attr">class</span>=<span class="string">"com.gtw.springioc.pojo.A"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">ref</span>=<span class="string">"b"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"b"</span> <span class="attr">class</span>=<span class="string">"com.gtw.springioc.pojo.B"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">ref</span>=<span class="string">"a"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div></pre></td></tr></table></figure><p>这是由于A被创建时，希望B被注入到自身，然而，此时B还有没有被创建，而且B也依赖于A，这样将导致Spring容器左右为难，无法满足两方需求，最后脑袋奔溃，抛出异常。解决这种困境的方式是使用Setter依赖，但还是会造成一些不必要的困扰，因此，强烈不建议在配置文件中使用循环依赖。</p><h2 id="自动装配与注解注入"><a href="#自动装配与注解注入" class="headerlink" title="自动装配与注解注入"></a>自动装配与注解注入</h2><h3 id="基于xml的自动装配"><a href="#基于xml的自动装配" class="headerlink" title="基于xml的自动装配"></a>基于xml的自动装配</h3><p>除了上述手动注入的情况，Spring还非常智能地为我们提供自动向Bean注入依赖的功能，这个过程一般被称为自动装配（autowiring）。博主认为这是一个非常酷的功能，当注入的bean特别多时，它将极大地节省编写注入程序的时间，因此在开发中，非常常见。Spring的自动装配有三种模式：<strong>byTpye(根据类型)</strong>，<strong>byName(根据名称)</strong>、<strong>constructor(根据构造函数)</strong>。</p><p>在byTpye模式中，Spring容器会基于反射查看bean定义的类，然后找到与依赖类型相同的bean注入到另外的bean中，这个过程需要借助setter注入来完成，因此必须存在set方法，否则注入失败。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//dao层</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserDaoImpl</span> <span class="keyword">implements</span> <span class="title">UserDao</span></span>&#123;</div><div class="line">    <span class="comment">//.......</span></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">done</span><span class="params">()</span></span>&#123;</div><div class="line">        System.out.println(<span class="string">"UserDaoImpl.invoke......"</span>);</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"><span class="comment">//service层</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserServiceImpl</span> <span class="keyword">implements</span> <span class="title">UserService</span> </span>&#123;</div><div class="line">    <span class="comment">//需要注入的依赖</span></div><div class="line">    <span class="keyword">private</span> UserDao userDao;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * set方法</div><div class="line">     * <span class="doctag">@param</span> userDao</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setUserDao</span><span class="params">(UserDao userDao)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.userDao = userDao;</div><div class="line">    &#125;</div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">done</span><span class="params">()</span></span>&#123;</div><div class="line">        userDao.done();</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>基于xml的配置如下，通过使用＜bean＞的autowire属性启动名称为userService的自动装配功能</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao"</span>  <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"><span class="comment">&lt;!-- byType 根据类型自动装配userDao--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userService"</span> <span class="attr">autowire</span>=<span class="string">"byType"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.UserServiceImpl"</span> /&gt;</span></div></pre></td></tr></table></figure><p>事实上byType模式可能存一种注入失败的情况，由于是基于类型的注入，因此当xml文件中存在多个相同类型名称不同的实例Bean时，Spring容器依赖注入仍然会失败，因为存在多种适合的选项，Spring容器无法知道该注入那种，此时我们需要为Spring容器提供帮助，指定注入那个Bean实例。可以通过＜bean＞标签的autowire-candidate设置为false来过滤那些不需要注入的实例Bean</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao"</span>  <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="comment">&lt;!-- autowire-candidate="false" 过滤该类型 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao2"</span> <span class="attr">autowire-candidate</span>=<span class="string">"false"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="comment">&lt;!-- byType 根据类型自动装配userDao--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userService"</span> <span class="attr">autowire</span>=<span class="string">"byType"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.UserServiceImpl"</span> /&gt;</span></div></pre></td></tr></table></figure><p>除了上述的解决方案外，还可采用byName模式的自动装配，此时Spring只会尝试将属性名与bean名称进行匹配，如果找到则注入依赖bean。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao"</span>  <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao2"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="comment">&lt;!-- byName 根据名称自动装配，找到UserServiceImpl名为 userDao属性并注入--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userService"</span> <span class="attr">autowire</span>=<span class="string">"byName"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.UserServiceImpl"</span> /&gt;</span></div></pre></td></tr></table></figure><p>需要了解的是如果Spring容器中没有找到可以注入的实例bean时，将不会向依赖属性值注入任何bean，这时依赖bean的属性可能为null，因此我们需要小心处理这种情况，避免不必要的奔溃。对于constructor模式，在该模式下Spring容器同样会尝试找到那些类型与构造函数相同匹配的bean然后注入。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserServiceImpl</span> <span class="keyword">implements</span> <span class="title">UserService</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> UserDao userDao;</div><div class="line">    <span class="comment">//constructor模式</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">UserServiceImpl</span><span class="params">(UserDao userDao)</span></span>&#123;</div><div class="line">        <span class="keyword">this</span>.userDao=userDao;</div><div class="line">    &#125;</div><div class="line"></div><div class="line"><span class="comment">//    /**</span></div><div class="line"><span class="comment">//     * set方法</span></div><div class="line"><span class="comment">//     * @param userDao</span></div><div class="line"><span class="comment">//     */</span></div><div class="line"><span class="comment">//    public void setUserDao(UserDao userDao) &#123;</span></div><div class="line"><span class="comment">//        this.userDao = userDao;</span></div><div class="line"><span class="comment">//    &#125;</span></div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">done</span><span class="params">()</span></span>&#123;</div><div class="line">        userDao.done();</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>基于xml配置：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao"</span>  <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"><span class="comment">&lt;!-- constructor自动装配userDao--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userService"</span> <span class="attr">autowire</span>=<span class="string">"constructor"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.UserServiceImpl"</span> /&gt;</span></div></pre></td></tr></table></figure><p>在实际测试中发现当出现多个bean实例时，如果含有名称与类中声明一样时仍然能正确找到对应类，如userDao、userDao2同时出现，而userService实现类中存在同名属性userDao，此时无需过滤也能正确注入：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="comment">&lt;!--没有过滤userDao2--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao2"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userService"</span> <span class="attr">autowire</span>=<span class="string">"constructor"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.UserServiceImpl"</span> /&gt;</span></div></pre></td></tr></table></figure><p>当只存在userDao2时，仍然能正常注入该类，如下形式</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!--只存在userDao2，仍然能正确注入--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao2"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userService"</span> <span class="attr">autowire</span>=<span class="string">"constructor"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.UserServiceImpl"</span> /&gt;</span></div></pre></td></tr></table></figure><p>但是当不存在userDao，只存在userDao2和userDao3时就不能注入了此时必须使用autowire-candidate=”false” 过滤该类型了。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!--只存在userDao2，userDao3 无法成功注入--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao2"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao3"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userService"</span> <span class="attr">autowire</span>=<span class="string">"constructor"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.UserServiceImpl"</span> /&gt;</span></div></pre></td></tr></table></figure><p>因此得出如下结论：<strong>在constructor模式下，存在单个实例则优先按类型进行参数匹配</strong>（无论名称是否匹配），当<strong>存在多个类型相同实例时，按名称优先匹配</strong>，如果没有找到对应名称，则注入失败，此时可以使用autowire-candidate=”false” 过滤来解决。</p><h3 id="基于注解的自动装配-Autowired-amp-Resource-amp-Value"><a href="#基于注解的自动装配-Autowired-amp-Resource-amp-Value" class="headerlink" title="基于注解的自动装配(@Autowired&amp;@Resource&amp;@Value)"></a>基于注解的自动装配(@Autowired&amp;@Resource&amp;@Value)</h3><h4 id="基于-Autowired注解的自动装配"><a href="#基于-Autowired注解的自动装配" class="headerlink" title="基于@Autowired注解的自动装配"></a>基于@Autowired注解的自动装配</h4><p>通过上述的分析，我们已对自动装配有所熟悉，但是在bean实例过多的情景下，手动设置自动注入属性还是不太完美，好在Spring 中引入了 @Autowired 注释，它可以对类成员变量、方法及构造函数进行标注，完成自动装配的工作。 通过 @Autowired的使用标注到成员变量时不需要有set方法，请注意@Autowired 默认按类型匹配的，先看示例用注解演示前面注入userDao实例的三种方式。当然使用注解前必须先注册注解驱动，这样注解才能被正确识别</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">&lt;!-- 使用注解时必须启动注解驱动 --&gt;</div><div class="line">&lt;context:annotation-config /&gt;</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserServiceImpl</span> <span class="keyword">implements</span> <span class="title">UserService</span> </span>&#123;</div><div class="line">    <span class="comment">//标注成员变量</span></div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="keyword">private</span> UserDao userDao;</div><div class="line">    <span class="comment">//标注构造方法</span></div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">UserServiceImpl</span><span class="params">(UserDao userDao)</span></span>&#123;</div><div class="line">        <span class="keyword">this</span>.userDao=userDao;</div><div class="line">    &#125;</div><div class="line">    <span class="comment">//标注set方法</span></div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setUserDao</span><span class="params">(UserDao userDao)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.userDao = userDao;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">done</span><span class="params">()</span></span>&#123;</div><div class="line">        userDao.done();</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>显然上述代码我们通过3种方式注入userDao实例，xml配置文件只需声明bean的实例即可，在实际开发中，我们只需选择其中一种进行注入操作即可，建议使用成员变量注入，这样可以省略set方法和构造方法，相当简洁。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserServiceImpl</span> <span class="keyword">implements</span> <span class="title">UserService</span> </span>&#123;</div><div class="line">    <span class="comment">//标注成员变量</span></div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="keyword">private</span> UserDao userDao;   </div><div class="line"> &#125;</div></pre></td></tr></table></figure><p>在@Autowired中还传递了一个required=false的属性，false指明当userDao实例存在就注入不存就忽略，如果为true，就必须注入，若userDao实例不存在，就抛出异常。由于<strong>默认情况下@Autowired是按类型匹配的(byType)，如果需要按名称(byName)匹配的话，可以使用@Qualifier注解与@Autowired结合</strong>，请注意必须在xml配置中启动注解驱动：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserServiceImpl</span> <span class="keyword">implements</span> <span class="title">UserService</span> </span>&#123;</div><div class="line">    <span class="comment">//标注成员变量</span></div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="meta">@Qualifier</span>(<span class="string">"userDao1"</span>)</div><div class="line">    <span class="keyword">private</span> UserDao userDao;   </div><div class="line"> &#125;</div></pre></td></tr></table></figure><p>使用byName模式，xml配置如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!-- 根据@Qualifier("userDao1")自动识别 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao1"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao2"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userService"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.UserServiceImpl"</span> /&gt;</span></div></pre></td></tr></table></figure><h4 id="基于-Resource注解的自动装配"><a href="#基于-Resource注解的自动装配" class="headerlink" title="基于@Resource注解的自动装配"></a>基于@Resource注解的自动装配</h4><p>与@Autowried具备相同功效的还有<strong>@Resource，默认按 byName模式自动注入,由J2EE提供</strong>，需导入Package: javax.annotation.Resource，<strong>可以标注在成员变量和set方法上，但无法标注构造函数</strong>。@Resource有两个中重要的属性：name和type。Spring容器对于@Resource注解的name属性解析为bean的名字，type属性则解析为bean的类型。因此使用name属性，则按byName模式的自动注入策略，如果使用type属性则按 byType模式自动注入策略。倘若既不指定name也不指定type属性，Spring容器将通过反射技术默认按byName模式注入。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//@Autowired标注成员变量</span></div><div class="line"><span class="meta">@Autowired</span></div><div class="line"><span class="meta">@Qualifier</span>(<span class="string">"userDao"</span>)</div><div class="line"><span class="keyword">private</span> UserDao userDao;  </div><div class="line"><span class="comment">//上述代码等价于@Resource</span></div><div class="line"><span class="meta">@Resource</span>(name=“userDao”)</div><div class="line"><span class="keyword">private</span> UserDao  userDao;<span class="comment">//用于成员变量</span></div><div class="line"></div><div class="line"><span class="comment">//也可以用于set方法标注</span></div><div class="line"><span class="meta">@Resource</span>(name=“userDao”)</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setUserDao</span><span class="params">(UserDao userDao)</span> </span>&#123;</div><div class="line">   <span class="keyword">this</span>.userDao= userDao;</div><div class="line">&#125;</div></pre></td></tr></table></figure><h4 id="基于-Value注解的自动装配以及properties文件读取"><a href="#基于-Value注解的自动装配以及properties文件读取" class="headerlink" title="基于@Value注解的自动装配以及properties文件读取"></a>基于@Value注解的自动装配以及properties文件读取</h4><p>关于@Autowired和@Resource都分析完了，但这里存在一个问题，上述两种自动装配的依赖注入并不适合简单值类型，<strong>对于int、boolean、long、String以及Enum等，对于这些类型，Spring容器也提供了@Value注入的方式</strong>，这是非常具备人性化的，可以解决很多硬编码问题。@Value接收一个String的值，该值指定了将要被注入到内置的java类型属性值，放心，不必关系类型转换，大多数情况下Spring容器都会自动处理好的。一般情况下@Value会与properties文件结合使用，也分两种情况一种是SpEL（有点类似于jsp的EL），另外一种是占位符方式，看一个简单例子jdbc.properties文件如下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">jdbc.driver=com.mysql.jdbc.Driver</div><div class="line">jdbc.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&amp;allowMultiQueries=true</div><div class="line">jdbc.username=root</div><div class="line">jdbc.password=root</div></pre></td></tr></table></figure><p>利用注解@Value获取jdbc.url和jdbc.username的值，实现如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserServiceImpl</span> <span class="keyword">implements</span> <span class="title">UserService</span> </span>&#123;</div><div class="line">    <span class="comment">//标注成员变量</span></div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="meta">@Qualifier</span>(<span class="string">"userDao"</span>)</div><div class="line">    <span class="keyword">private</span> UserDao userDao;</div><div class="line">    <span class="comment">//占位符方式</span></div><div class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;jdbc.url&#125;"</span>)</div><div class="line">    <span class="keyword">private</span> String url;</div><div class="line">    <span class="comment">//SpEL表达方式，其中代表xml配置文件中的id值configProperties</span></div><div class="line">    <span class="meta">@Value</span>(<span class="string">"#&#123;configProperties['jdbc.username']&#125;"</span>)</div><div class="line">    <span class="keyword">private</span> String userName;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">done</span><span class="params">()</span></span>&#123;</div><div class="line">        System.out.println(<span class="string">"url:"</span>+url);</div><div class="line">        System.out.println(<span class="string">"username:"</span>+userName);</div><div class="line">        userDao.done();</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>基于xml的配置如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></div><div class="line">       <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></div><div class="line">       <span class="attr">xmlns:context</span>=<span class="string">"http://www.springframework.org/schema/context"</span></div><div class="line">       <span class="attr">xmlns:util</span>=<span class="string">"http://www.springframework.org/schema/util"</span></div><div class="line">       <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</span></div><div class="line">    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"&gt;</div><div class="line"></div><div class="line">    <span class="comment">&lt;!--基于占位符方式 配置单个properties --&gt;</span></div><div class="line">    <span class="comment">&lt;!--&lt;context:property-placeholder location="conf/jdbc.properties"/&gt;--&gt;</span></div><div class="line">    <span class="comment">&lt;!--基于占位符方式 配置多个properties --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"propertyConfigurer"</span> <span class="attr">class</span>=<span class="string">"org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"location"</span> <span class="attr">value</span>=<span class="string">"conf/jdbc.properties"</span>/&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"></div><div class="line">    <span class="comment">&lt;!--基于SpEL表达式 配置多个properties id值为configProperties 提供java代码中使用 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"configProperties"</span> <span class="attr">class</span>=<span class="string">"org.springframework.beans.factory.config.PropertiesFactoryBean"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"locations"</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">list</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">value</span>&gt;</span>classpath:/conf/jdbc.properties<span class="tag">&lt;/<span class="name">value</span>&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">list</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"></div><div class="line">    <span class="comment">&lt;!--基于SpEL表达式 配置单个properties --&gt;</span></div><div class="line">    <span class="comment">&lt;!--&lt;util:properties id="configProperties" location="classpath:conf/jdbc.properties"/&gt;--&gt;</span></div><div class="line"></div><div class="line">    <span class="comment">&lt;!--注解驱动 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">context:annotation-config</span>/&gt;</span></div><div class="line"></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span>/&gt;</span></div><div class="line"></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userDao2"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.UserDaoImpl"</span>/&gt;</span></div><div class="line"></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"userService"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.UserServiceImpl"</span>/&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></div></pre></td></tr></table></figure><h1 id="IOC容器管理-bean"><a href="#IOC容器管理-bean" class="headerlink" title="IOC容器管理 bean"></a>IOC容器管理 bean</h1><h2 id="Bean的命名以及实例化方法"><a href="#Bean的命名以及实例化方法" class="headerlink" title="Bean的命名以及实例化方法"></a>Bean的命名以及实例化方法</h2><h3 id="Bean的命名"><a href="#Bean的命名" class="headerlink" title="Bean的命名"></a>Bean的命名</h3><p>每一个交给Spring IOC（后面统称Spring容器）容器创建的对象必须被分配至少一个名称，如果开发者没有提供，Spring容器将会为其分配一个内部名称，通过Bean的名称，我们可以在其他类中查找该类并使用它，如前面的案例，也是通过Bean名称获取到实际对象并执行对应的操作。在基于xml的配置信息中，可以使用id属性来为一个Bean分配名称，在同一个xml配置文件中，id必须是唯一的，但不同的xml可以相同，当然还可以使用name来为Bean分配名称，name属性可以分配多个名称，此时可使用空格、逗号、分号来分离给定Bean分配多个名称，而id属性则无法这样使用。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!-- name属性配置多个名称 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountDao,accountDao2"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</span></div><div class="line"><span class="comment">&lt;!-- id属性配置唯一名称而且不能与name相同--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"accountDaoId"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</span></div></pre></td></tr></table></figure><p>在name属性中声明了两个名称，除了第一个名称外，其他的名称都被称为别名(aliase)。除了在Bean中定义名称外，还可利用＜alias＞标签向Bean赋予别名：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"accountDaoId"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</span></div><div class="line"><span class="comment">&lt;!-- name属性指明要给那个Bean赋予别名,alias则指明赋予的别名--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">alias</span> <span class="attr">name</span>=<span class="string">"accountDaoId"</span> <span class="attr">alias</span>=<span class="string">"accountDao3"</span> /&gt;</span></div></pre></td></tr></table></figure><p>显然如果我们想要配置的Bean对象已存在，并且希望向一些Bean赋予特别的名称，此时别名就相当有用了。上述的Bean对象声明使用都在xml内声明手动声明的方式，一旦Bean对象多起来，管理Bean可能会发生繁琐的情况，为了Spring提供了基于Java注解的配置方式，下面分别使用org.springframework.stereotype.Service（@Service）和org.springframework.stereotype.Repository（@Repository）声明AccountServiceImpl和AccountDaoImpl类，使用@Autowired注解注入accountDao（需要在xml声明注解驱动）</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//@Component 相同效果</span></div><div class="line"><span class="meta">@Service</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AccountServiceImpl</span> <span class="keyword">implements</span> <span class="title">AccountService</span> </span>&#123;</div><div class="line">  <span class="meta">@Autowired</span></div><div class="line">  <span class="keyword">private</span> AccountDao accountDao;</div><div class="line">&#125;</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//@Component 相同效果</span></div><div class="line"><span class="meta">@Repository</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AccountDaoImpl</span> <span class="keyword">implements</span> <span class="title">AccountDao</span></span>&#123;</div><div class="line"><span class="comment">//......</span></div><div class="line">&#125;</div></pre></td></tr></table></figure><p>有了注解声明，我们就不需要在xml中声明以上两个Bean，但需要明确告诉Spring注解的Bean在那些包下，因此需要添加包扫描机制，此时需要启用Spring的context命名空间：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></div><div class="line">       <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></div><div class="line">       <span class="attr">xmlns:context</span>=<span class="string">"http://www.springframework.org/schema/context"</span></div><div class="line">       <span class="attr">xsi:schemaLocation</span>=<span class="string">"</span></div><div class="line">        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</div><div class="line">        http://www.springframework.org/schema/context </div><div class="line">        http://www.springframework.org/schema/context/spring-context.xsd</div><div class="line">        "&gt;</div><div class="line">    <span class="comment">&lt;!-- 声明包扫描 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">"com.gtw.spring.springIoc"</span> /&gt;</span></div><div class="line"></div><div class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></div></pre></td></tr></table></figure><p>以上的声明方式与之前在xml声明bean的效果相同。这里我们需要明白可以使用@Component注解达到与@Service和@Repository的效果，@Component与@Service的含义并无差异，只不过@Service更能让我们明白该类为业务类罢了。至于@Repository在表示数据访问层含义的同时还能够启用与Spring数据访问相关链的其他功能（这个在Spring jdbc相关内容时再详谈，此时我们只需明白@Repository与@Component等效即可）,同时还可给@Component、@Service和@Repository输入一个String值的名称，如果没有提供名称，那么默认情况下就是一个简单的类名(第一个字符小写)变成Bean名称。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Service</span>(<span class="string">"accountService"</span>)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AccountServiceImpl</span> <span class="keyword">implements</span> <span class="title">AccountService</span> </span>&#123;</div><div class="line">  <span class="meta">@Autowired</span></div><div class="line">  <span class="keyword">private</span> AccountDao accountDao;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="meta">@Repository</span>(<span class="string">"accountDao"</span>)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AccountDaoImpl</span> <span class="keyword">implements</span> <span class="title">AccountDao</span></span>&#123;</div><div class="line"><span class="comment">//......</span></div><div class="line">&#125;</div></pre></td></tr></table></figure><p>因此到这我们也就知道了，Spring的框架中提供了与@Component注解等效的三个注解，@Repository 用于对DAO实现类进行标注，@Service 用于对Service实现类进行标注，@Controller 用于对Controller实现类进行标注（web层控制器），同时也了解了Spring 容器通过xml的bean标签配置和java注解两种方式声明的Bean对象，我们可以单独使用其中一种也可以两种混合使用，取决于各自的需求。</p><h3 id="Bean实例化方法"><a href="#Bean实例化方法" class="headerlink" title="Bean实例化方法"></a>Bean实例化方法</h3><p>在日常开发中创建对象的最常用的就是通过类的构造方法，事实上Spring容器也是正常情况下也是通过构造方法创建bean的。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Account</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> String name;</div><div class="line">    <span class="keyword">private</span> String pwd;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 默认构造</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Account</span><span class="params">()</span></span>&#123;</div><div class="line"></div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 带参数的构造</div><div class="line">     * <span class="doctag">@param</span> name</div><div class="line">     * <span class="doctag">@param</span> pwd</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Account</span><span class="params">(String name, String pwd)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.name = name;</div><div class="line">        <span class="keyword">this</span>.pwd = pwd;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.name = name;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPwd</span><span class="params">(String pwd)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.pwd = pwd;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> name;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getPwd</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> pwd;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>在xml中配置</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!-- 默认构造创建,并通过property 注入属性值 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"account"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.pojo.Account"</span> &gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"name"</span> <span class="attr">value</span>=<span class="string">"Jack"</span> /&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"pwd"</span> <span class="attr">value</span>=<span class="string">"123"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"></div><div class="line"><span class="comment">&lt;!-- 带参构造创建,并通过constructor-arg注入属性值 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"account2"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.pojo.Account"</span> &gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">"name"</span> <span class="attr">value</span>=<span class="string">"Jack"</span> /&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">"pwd"</span> <span class="attr">value</span>=<span class="string">"1234"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div></pre></td></tr></table></figure><p>除了构造创建外还存在另外两种比较冷门的创建的方式即<strong>静态方法构造和实例工厂方法构造</strong>，下面我们简单看一个例子即可：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PojoFactory</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 静态工厂创建</div><div class="line">     * <span class="doctag">@return</span></div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Account <span class="title">createAccount</span><span class="params">()</span></span>&#123;</div><div class="line">        Account account=<span class="keyword">new</span> Account();</div><div class="line">        account.setName(<span class="string">"Jack"</span>);</div><div class="line">        account.setPwd(<span class="string">"1234"</span>);</div><div class="line">        <span class="keyword">return</span> account;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * 通过工厂实例创建</div><div class="line">     * <span class="doctag">@return</span></div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> Account <span class="title">createAccount2</span><span class="params">()</span></span>&#123;</div><div class="line">        Account account=<span class="keyword">new</span> Account();</div><div class="line">        account.setName(<span class="string">"Jack"</span>);</div><div class="line">        account.setPwd(<span class="string">"1234"</span>);</div><div class="line">        <span class="keyword">return</span> account;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>xml配置如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!-- 静态工厂创建,调用静态方法createAccount --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"account3"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.conf.PojoFactory"</span> </span></div><div class="line">  <span class="attr">factory-method</span>=<span class="string">"createAccount"</span>/&gt;</div><div class="line"></div><div class="line"><span class="comment">&lt;!-- 工厂实例创建,先创建工厂类在调用方法createAccount2 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"factory"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.conf.PojoFactory"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"account4"</span> <span class="attr">factory-bean</span>=<span class="string">"factory"</span>  <span class="attr">factory-method</span>=<span class="string">"createAccount2"</span>/&gt;</span></div></pre></td></tr></table></figure><p>后面两种方式简单了解即可，一般很少使用。常用的还是构造创建，开发中使用构造实例化bean即可。</p><h2 id="Bean的重写机制"><a href="#Bean的重写机制" class="headerlink" title="Bean的重写机制"></a>Bean的重写机制</h2><p>Bean的重写机制并没有那么神秘，主要是当不同的xml文件中出现同名id属性的bean时读取的优先级问题，同样简单看个例子就明白了。定义两个spring的配置文件并同时加载它们：spring-ioc.xml</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></div><div class="line">  <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></div><div class="line">  <span class="attr">xmlns:context</span>=<span class="string">"http://www.springframework.org/schema/context"</span></div><div class="line">  <span class="attr">xsi:schemaLocation</span>=<span class="string">"</span></div><div class="line">http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</div><div class="line">http://www.springframework.org/schema/context</div><div class="line">http://www.springframework.org/schema/context/spring-context.xsd</div><div class="line">"&gt;</div><div class="line"><span class="comment">&lt;!-- 默认构造创建,并通过property 注入属性值 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"account"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.pojo.Account"</span> &gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"name"</span> <span class="attr">value</span>=<span class="string">"I am SpringIOC1"</span> /&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"pwd"</span> <span class="attr">value</span>=<span class="string">"123"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></div></pre></td></tr></table></figure><p>spring-ioc2.xml</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></div><div class="line">  <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></div><div class="line">  <span class="attr">xmlns:context</span>=<span class="string">"http://www.springframework.org/schema/context"</span></div><div class="line">  <span class="attr">xsi:schemaLocation</span>=<span class="string">"</span></div><div class="line">http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</div><div class="line">http://www.springframework.org/schema/context</div><div class="line">http://www.springframework.org/schema/context/spring-context.xsd</div><div class="line">"&gt;</div><div class="line"><span class="comment">&lt;!-- 默认构造创建,并通过property 注入属性值 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"account"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.pojo.Account"</span> &gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"name"</span> <span class="attr">value</span>=<span class="string">"I am SpringIOC2"</span> /&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"pwd"</span> <span class="attr">value</span>=<span class="string">"123"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></div></pre></td></tr></table></figure><p>获取bean并调用</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Test</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test1</span><span class="params">()</span>  </span>&#123;</div><div class="line">  ApplicationContext applicationContext=<span class="keyword">new</span></div><div class="line">          ClassPathXmlApplicationContext(<span class="string">"spring/spring-ioc.xml"</span>,<span class="string">"spring/spring-ioc2.xml"</span>);</div><div class="line">    Account account= (Account) applicationContext.getBean(<span class="string">"account"</span>);</div><div class="line">    System.out.println(<span class="string">"调用结果:"</span>+account.getName());</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>执行结果：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">调用结果:I am SpringIOC2</div></pre></td></tr></table></figure><p>显然在<strong>不同的xml配置文件中使用相同id命名，并声明相同类型的bean对象时，spring容器会默认加载最后添加的</strong>spring-ioc2.xml中account而忽略spring-ioc.xml中的account，也就是说Bean的重写机制原则是当声明的bean的名称一样时，后者会覆盖前者。我们还需要明确的一点时，在web应用开发过程中，一般都会将配置进行分层管理，然后通过一个主springApplication.xml来聚合它，在这样的情况下分层的配置文件属于springApplication.xml的子文件，在这样的关系遇到上述的情况一般都子文件的优先级高，因此会加载子文件的bean。如在spring-ioc.xml主文件导入子文件spring-ioc2.xml:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></div><div class="line">       <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></div><div class="line">       <span class="attr">xmlns:context</span>=<span class="string">"http://www.springframework.org/schema/context"</span></div><div class="line">       <span class="attr">xsi:schemaLocation</span>=<span class="string">"</span></div><div class="line">        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</div><div class="line">        http://www.springframework.org/schema/context</div><div class="line">        http://www.springframework.org/schema/context/spring-context.xsd</div><div class="line">        "&gt;</div><div class="line"></div><div class="line">    <span class="comment">&lt;!-- 默认构造创建,并通过property 注入属性值 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"account"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.pojo.Account"</span> &gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"name"</span> <span class="attr">value</span>=<span class="string">"I am SpringIOC1"</span> /&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"pwd"</span> <span class="attr">value</span>=<span class="string">"123"</span> /&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"></div><div class="line">    <span class="comment">&lt;!-- 导入的子文件 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">import</span> <span class="attr">resource</span>=<span class="string">"spring-ioc2.xml"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></div></pre></td></tr></table></figure><p>运行代码：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Test</span></div><div class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test1</span><span class="params">()</span>  </span>&#123;</div><div class="line">    ApplicationContext applicationContext=<span class="keyword">new</span></div><div class="line">            ClassPathXmlApplicationContext(<span class="string">"spring/spring-ioc.xml"</span>);</div><div class="line">      Account account= (Account) applicationContext.getBean(<span class="string">"account"</span>);</div><div class="line">      System.out.println(<span class="string">"调用结果:"</span>+account.getName());</div><div class="line">  &#125;</div></pre></td></tr></table></figure><p>上述代码会优先加载spring-ioc2.xml中的account而忽略spring-ioc.xml中的account，效果与前面的代码相同。</p><p>关于分层管理开发一般按如下方式（这样的好处是脉络清晰，方便管理）：</p><p>spring-web.xml文件：web层相关bean声明<br>spring-service.xml文件：service层相关bean声明<br>spring-dao.xml文件：dao层相关bean声明<br>spring-tx.xml文件：事务相关bean和规则声明<br>spring-security.xml文件：安全相关声明<br>spring-application.xml 文件：汇聚文件或总bean声明。</p><h2 id="Bean的作用域"><a href="#Bean的作用域" class="headerlink" title="Bean的作用域"></a>Bean的作用域</h2><h3 id="Singleton作用域"><a href="#Singleton作用域" class="headerlink" title="Singleton作用域"></a>Singleton作用域</h3><p>所谓Bean的作用域是指spring容器创建Bean后的生存周期即由创建到销毁的整个过程。之前我们所创建的所有Bean其作用域都是Singleton，这是Spring默认的，在这样的作用域下，每一个Bean的实例只会被创建一次，而且Spring容器在整个应用程序生存期中都可以使用该实例。因此之前的代码中spring容器创建Bean后，通过代码获取的bean，无论多少次，都是同一个Bean的实例。我们可使用＜bean＞标签的scope属性来指定一个Bean的作用域，如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!-- 默认情况下无需声明Singleton --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">scope</span>=<span class="string">"singleton"</span>    </span></div><div class="line"><span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</div></pre></td></tr></table></figure><h3 id="prototype作用域"><a href="#prototype作用域" class="headerlink" title="prototype作用域"></a>prototype作用域</h3><p>除了Singleton外还有另外一种比较常用的作用域，prototype，它代表每次获取Bean实例时都会新创建一个实例对象，类似new操作符。我们来简单测试一下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!-- 作用域：prototype --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">scope</span>=<span class="string">"prototype"</span>     <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</span></div></pre></td></tr></table></figure><p>测试代码：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Test</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test2</span><span class="params">()</span>  </span>&#123;</div><div class="line">    ApplicationContext applicationContext=<span class="keyword">new</span></div><div class="line">            ClassPathXmlApplicationContext(<span class="string">"spring/spring-ioc.xml"</span>);</div><div class="line">    AccountDao accountDao1 = (AccountDao) applicationContext.getBean(<span class="string">"accountDao"</span>);</div><div class="line">    AccountDao accountDao2 = (AccountDao) applicationContext.getBean(<span class="string">"accountDao"</span>);</div><div class="line">    System.out.println(<span class="string">"accountDao1地址:"</span>+accountDao1.toString());</div><div class="line">    System.out.println(<span class="string">"accountDao2地址:"</span>+accountDao2.toString());</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>执行结果：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">accountDao2地址:com.gtw.spring.springIoc.dao.impl.AccountDaoImpl@401e7803</div><div class="line">accountDao2地址:com.gtw.spring.springIoc.dao.impl.AccountDaoImpl@a3165b97</div></pre></td></tr></table></figure><p>显然是两个不同的实例对象。当然我们也可通过注解来声明作用域：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Scope</span>(<span class="string">"prototype"</span>)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AccountDaoImpl</span> </span>&#123;</div><div class="line">    <span class="comment">//......</span></div><div class="line">&#125;</div></pre></td></tr></table></figure><p>这里还需要说明一种特殊的情景，当一个作用域为Singleton的Bean依赖于一个作用域为prototype的Bean时如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="comment">&lt;!-- 作用域prototype--&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">scope</span>=<span class="string">"prototype"</span></span></div><div class="line"><span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</div><div class="line"><span class="comment">&lt;!-- 作用域Singleton --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountService"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.AccountServiceImpl"</span>&gt;</span></div><div class="line">    <span class="comment">&lt;!-- 注入作用域为prototype的accountDao对象,需要set方法 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">ref</span>=<span class="string">"accountDao"</span>/&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div></pre></td></tr></table></figure><p>在这样的情况下希望的是每次getBean(“accountService”)处理的都是一个新的accountDao实例对象，但是由于accountService的依赖是在Bean被创建时注入的，而且accountService是一个Singleton，整个生存周期中只会创建一次，因此它所依赖的accountDao实例对象也只会被注入一次，此后不会再注入任何新的accountDao实例对象。</p><p>为了解决这种困境，只能放弃使用依赖注入的功能，使用代码实现，如下：通过实现ApplicationContextAware接口，重写setApplicationContext，这样的话Spring容器<strong>在创建AccountServiceImpl实例时会自动注入ApplicationContext对象</strong>，此时便可以通过ApplicationContext获取accountDao实例了，这样可以保证每次获取的accountDao实例都是新的（这里的代码只是演示该过程，实际开发中一般不会要求accountDao每次都是新实例，因为accountDao无需记录状态信息，即无状态bean,一般默认singleton即可）</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">scope</span>=<span class="string">"prototype"</span>  <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</span></div><div class="line"><span class="comment">&lt;!-- accountDao通过代码注入 --&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountService"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.AccountServiceImpl"</span> /&gt;</span></div></pre></td></tr></table></figure><p>代码注入示范：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AccountServiceImpl</span> <span class="keyword">implements</span> <span class="title">AccountService</span> , <span class="title">ApplicationContextAware</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> ApplicationContext applicationContext;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doSomething</span><span class="params">()</span> </span>&#123;</div><div class="line">        System.out.println(<span class="string">"AccountServiceImpl#doSomething......"</span>);</div><div class="line">        System.out.println(<span class="string">"getAccountDao....."</span>+ getAccountDao().toString());</div><div class="line"></div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setApplicationContext</span><span class="params">(ApplicationContext applicationContext)</span> <span class="keyword">throws</span> BeansException </span>&#123;</div><div class="line">        <span class="keyword">this</span>.applicationContext=applicationContext;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> AccountDao <span class="title">getAccountDao</span><span class="params">()</span></span>&#123;</div><div class="line">        <span class="keyword">return</span> applicationContext.getBean(AccountDao.class);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>测试代码：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//加载配置文件</span></div><div class="line">ApplicationContext applicationContext=<span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="string">"spring/spring-ioc.xml"</span>);</div><div class="line"><span class="comment">//测试获取不同实例的AccountDao</span></div><div class="line">AccountService accountService= (AccountService) applicationContext.getBean(<span class="string">"accountService"</span>);</div><div class="line">accountService.doSomething();</div><div class="line">AccountService accountService1= (AccountService) applicationContext.getBean(<span class="string">"accountService"</span>);</div><div class="line">accountService1.doSomething();</div></pre></td></tr></table></figure><p>显然这样的方式，每次获取的daoAccount都不一样，也就解决上述的问题，另外的一种情况是当一个作用域为propotype的Bean依赖于一个Singleton作用域的Bean时，解决方案跟上述是相同的。请注意，<strong>当一个Bean被设置为prototype 后Spring就不会对一个bean的整个生命周期负责，容器在初始化、配置、装饰或者是装配完一个prototype实例后，将它交给客户端，随后就对该prototype实例不闻不问了。</strong>因此我们需要慎用它，一般情况下，对有状态的bean应该使用prototype作用域，而对无状态的bean则应该使用singleton作用域。所谓<strong>有状态就是该bean有保存信息的能力，不能共享，否则会造成线程安全问题</strong>，而无状态则不保存信息，是线程安全的，可以共享，spring中大部分bean都是Singleton，整个生命周期过程只会存在一个。</p><h3 id="request与session作用域"><a href="#request与session作用域" class="headerlink" title="request与session作用域"></a>request与session作用域</h3><p>在spring2.5中专门针对Web应该程序引进了request和session这两种作用域。关于request作用域，对于每次HTTP请求到达应用程序，Spring容器会创建一个全新的Request作用域的bean实例，且该bean实例仅在当前HTTP request内有效，整个请求过程也只会使用相同的bean实例，因此我们可以根据需要放心的更改所建实例的内部状态，而其他请求HTTP请求则创建新bean的实例互不干扰，当处理请求结束，request作用域的bean实例将被销毁，如在接收参数时可能需要一个bean实例来装载一些参数，显然每次请求参数几乎不会相同，因此希望bean实例每次都是足够新的而且只在request作用域范围内有效。关于Session可能你也已猜到，每当创建一个新的HTTP Session时就会创建一个Session作用域的Bean，并该实例bean伴随着会话的存在而存在。下面看一个测试程序：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Component</span></div><div class="line"><span class="meta">@Scope</span>(value = <span class="string">"singleton"</span>)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonBean</span> </span>&#123;</div><div class="line">    <span class="comment">//......</span></div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="meta">@Component</span></div><div class="line"><span class="meta">@Scope</span>(value = <span class="string">"prototype"</span> , proxyMode = ScopedProxyMode.TARGET_CLASS)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PrototypeBean</span> </span>&#123;</div><div class="line">    <span class="comment">//......</span></div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="meta">@Component</span></div><div class="line"><span class="meta">@Scope</span>(value = <span class="string">"request"</span> , proxyMode = ScopedProxyMode.TARGET_CLASS)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RequestBean</span> </span>&#123;</div><div class="line">    <span class="comment">//......</span></div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="meta">@Component</span></div><div class="line"><span class="meta">@Scope</span>(value = <span class="string">"session"</span> , proxyMode = ScopedProxyMode.TARGET_CLASS)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SessionBean</span> </span>&#123;</div><div class="line">    <span class="comment">//........</span></div><div class="line">&#125;</div></pre></td></tr></table></figure><p>上述代码，分别创建4个不同作用域的Bean，并使用注解的方式开发，@Component表名它们是组件类，需要Spring容器帮忙创建，@Scope注明作用域，value指明是哪种作用域，除了SingletonBean外，其它Bean还使用proxyMode指明哪种代理模式创建，这里没有接口，因此使用CGLib代理生成（后面会分析为什么这么做）。接着需要在xml注明扫描包告诉Spring容器它们在哪里（4个类都声明在com.gtw.spring.dto包下）。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">&lt;!-- 包扫描 --&gt;</div><div class="line">&lt;context:component-scan  base-package=&quot;com.gtw.spring.dto&quot; /&gt;</div></pre></td></tr></table></figure><p>使用SpringMVC创建Web访问层：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Controller</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BookController</span></span>&#123;</div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="keyword">private</span> RequestBean requestBean;</div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="keyword">private</span> SessionBean sessionBean;</div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="keyword">private</span> PrototypeBean prototypeBean;</div><div class="line">    <span class="meta">@Autowired</span></div><div class="line">    <span class="keyword">private</span> SingletonBean singletonBean;</div><div class="line"></div><div class="line"></div><div class="line">    <span class="meta">@RequestMapping</span>(value = <span class="string">"/test"</span>)</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test</span><span class="params">()</span></span>&#123;</div><div class="line">        print();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>&#123;</div><div class="line">        System.out.println(<span class="string">"first  time singleton is :"</span> + singletonBean);</div><div class="line">        System.out.println(<span class="string">"second time singleton is :"</span> + singletonBean);</div><div class="line"></div><div class="line">        System.out.println(<span class="string">"first  time prototype is :"</span> + prototypeBean);</div><div class="line">        System.out.println(<span class="string">"second time prototype is :"</span> + prototypeBean);</div><div class="line"></div><div class="line">        System.out.println(<span class="string">"first  time requestBean is :"</span> + requestBean);</div><div class="line">        System.out.println(<span class="string">"second time requestBean is :"</span> + requestBean);</div><div class="line"></div><div class="line">        System.out.println(<span class="string">"first  time sessionBean is :"</span> + sessionBean);</div><div class="line">        System.out.println(<span class="string">"second time sessionBean is :"</span> + sessionBean);</div><div class="line"></div><div class="line">        System.out.println(<span class="string">"==========================================="</span>);</div><div class="line">    &#125;</div></pre></td></tr></table></figure><p>现在启动tomcat服务器使用Chrome浏览器进行连续两次访问结果如下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">first  time singletonBean is :com.gtw.spring.dto.SingletonBean@2ebdd720</div><div class="line">second time singletonBean is :com.gtw.spring.dto.SingletonBean@2ebdd720</div><div class="line">first  time prototypeBean is :com.gtw.spring.dto.PrototypeBean@1ed53cde</div><div class="line">second time prototypeBean is :com.gtw.spring.dto.PrototypeBean@35c052be</div><div class="line">first  time requestBean is :com.gtw.spring.dto.RequestBean@15b9dfe1</div><div class="line">second time requestBean is :com.gtw.spring.dto.RequestBean@15b9dfe1</div><div class="line">first  time sessionBean is :com.gtw.spring.dto.SessionBean@5b355dae</div><div class="line">second time sessionBean is :com.gtw.spring.dto.SessionBean@5b355dae</div><div class="line">===========================================</div><div class="line">first  time singletonBean is :com.gtw.spring.dto.SingletonBean@2ebdd720</div><div class="line">second time singletonBean is :com.gtw.spring.dto.SingletonBean@2ebdd720</div><div class="line">first  time prototypeBean is :com.gtw.spring.dto.PrototypeBean@7775fd09</div><div class="line">second time prototypeBean is :com.gtw.spring.dto.PrototypeBean@79b20d97</div><div class="line">first  time requestBean is :com.gtw.spring.dto.RequestBean@7d8d9679</div><div class="line">second time requestBean is :com.gtw.spring.dto.RequestBean@7d8d9679</div><div class="line">first  time sessionBean is :com.gtw.spring.dto.SessionBean@5b355dae</div><div class="line">second time sessionBean is :com.gtw.spring.dto.SessionBean@5b355dae</div><div class="line">===========================================</div></pre></td></tr></table></figure><p>显然singletonBean永远只有一个实例，而PrototypeBean则每次被获取都会创建新的实例，对应RequestBean，在同一次Http请求过程中是同一个实例，当请求结束，RequestBean也随着销毁，在新的Http请求则会生成新的RequestBean实例，对于SessionBean，由于是在同一个浏览器中访问属于同一次会话，因此SessionBean实例都是同一个实例对象。现在使用另外一个浏览器启动访问，观察SessionBean是否变化。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">first  time singletonBean is :com.gtw.spring.dto.SingletonBean@2ebdd720</div><div class="line">second time singletonBean is :com.gtw.spring.dto.SingletonBean@2ebdd720</div><div class="line">first  time prototypeBean is :com.gtw.spring.dto.PrototypeBean@5a85c6a7</div><div class="line">second time prototypeBean is :com.gtw.spring.dto.PrototypeBean@54423387</div><div class="line">first  time requestBean is :com.gtw.spring.dto.RequestBean@507dadd7</div><div class="line">second time requestBean is :com.gtw.spring.dto.RequestBean@507dadd7</div><div class="line">first  time sessionBean is :com.gtw.spring.dto.SessionBean@157f39bc</div><div class="line">second time sessionBean is :com.gtw.spring.dto.SessionBean@157f39bc</div><div class="line">===========================================</div></pre></td></tr></table></figure><p>显然SessionBean已改变，也就说明不同的会话中SessionBean实例是不同的。但我们还是很诧异，为什么需要在其他3种作用域上设置代理模式？事实上这个问题的本质与前面Singleton作用域的bean依赖于Prototype作用域的bean原理是相同，Prototype前面已分析过了（使用注解时也必须声明代理模式），这里我们主要分析request和session作用域，由于Spring容器只会在创建bean实例时帮助我们注入该实例bean所依赖的其他bean实例，而且只会注入一次，这并不是request、session作用域所希望看到的，毕竟它们都需要在不同的场景下注入新的实例对象而不是唯一不变的实例对象。</p><p>为了解决这种困境，必须放弃直接在xml中注入bean实例，改用java代码方式(实现ApplicationContextAware接口)或者注解的方式(@Autowired)注入。示例中选择了后者，并在bean的声明中声明了动态代理模式（关于动态代理自行查阅相关资料），幸运地是，Spring容器足够聪明，以至于spring容器通过代理的方式生成新的代理实例bean，以此来满足创建新实例的需求。</p><p>在程序运行过程中，当一个方法调用到达该代理对象时，Spring容器便尝试在当前的请求(Request)或者会话(Session)获取目标对象Bean(真正的实例Bean)。如果已存在则使用该Bean，否则，代理方法将创建新实例bean处理请求或者会话，请注意，这里指的的是一次Http请求或者一次会话的过程。如果希望request和session作用域通过xml配置文件方式声明时必须在＜bean＞标签中放置＜aop:scoped-proxy＞作为子标签，该作用于注解声明代理模式效果相同(需要引用aop命名空间，关于aop不清楚的，这里可简单理解为声明代理即可)。</p><p>请注意，经过测试这种声明代理的方式不适合prototype作用域，该作用域生效的方式目前测试中只有基于注解方式和前面基于实现ApplicationContextAware接口两种方式。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</div><div class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></div><div class="line"> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="attr">xmlns:mvc</span>=<span class="string">"http://www.springframework.org/schema/mvc"</span></div><div class="line"> <span class="attr">xmlns:context</span>=<span class="string">"http://www.springframework.org/schema/context"</span></div><div class="line"> <span class="attr">xmlns:aop</span>=<span class="string">"http://www.springframework.org/schema/aop"</span></div><div class="line"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans</span></div><div class="line">http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc</div><div class="line">http://www.springframework.org/schema/mvc/spring-mvc.xsd</div><div class="line">http://www.springframework.org/schema/context</div><div class="line">http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"</div><div class="line">&gt;</div><div class="line"></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"requestBean"</span> <span class="attr">scope</span>=<span class="string">"request"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.dto.RequestBean"</span> &gt;</span></div><div class="line">    <span class="comment">&lt;!-- 声明aop代理 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">aop:scoped-proxy</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"></div><div class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"sessionBean"</span> <span class="attr">scope</span>=<span class="string">"request"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.dto.SessionBean"</span> &gt;</span></div><div class="line">    <span class="comment">&lt;!-- 声明aop代理 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">aop:scoped-proxy</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></div></pre></td></tr></table></figure><p>最后还有一点需要明确的是，如果web层适用的是SpringMVC处理web请求，则不需要做任何事情就可以使Request和Session作用域生效。但倘若适用其他web层框架的实现，务必需要在web.xml中声明如下监听器，以便使Request和Session作用域正常工作：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">web-app</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">listener</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">listener-class</span>&gt;</span> org.springframework.web.context.request.RequestContextListener <span class="tag">&lt;<span class="name">listener-class</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">listener</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">web-app</span>&gt;</span></div></pre></td></tr></table></figure><h3 id="globalSession作用域"><a href="#globalSession作用域" class="headerlink" title="globalSession作用域"></a>globalSession作用域</h3><p>这种作用域类似于Session作用域，相当于全局变量，类似Servlet的Application，适用基于portlet的web应用程序，请注意，portlet在这指的是分布式开发，而不是portlet语言开发。</p><h2 id="Bean的延长加载"><a href="#Bean的延长加载" class="headerlink" title="Bean的延长加载"></a>Bean的延长加载</h2><p>在某些情况下，我们可能希望把bean的创建延迟到使用阶段，以免消耗不必要的内存，Spring也非常自愿地支持了延迟bean的初始化。因此可以在配置文件中定义bean的延迟加载，这样Spring容器将会延迟bean的创建直到真正需要时才创建。通常情况下，从一个已创建的bean引用另外一个bean，或者显示查找一个bean时会触发bean的创建即使配置了延迟属性，因此如果Spring容器在启动时创建了那些设为延长加载的bean实例，不必惊讶，可能那些延迟初始化的bean可能被注入到一个非延迟创建且作用域为singleton的bean。<strong>在xml文件中使用bean的lazy-init属性可以配置改bean是否延迟加载</strong>，如果需要配置整个xml文件的bean都延迟加载则使用defualt-lazy-init属性，请注意lazy-init属性会覆盖defualt-lazy-init属性。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></div><div class="line">       <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></div><div class="line">       <span class="attr">xmlns:context</span>=<span class="string">"http://www.springframework.org/schema/context"</span></div><div class="line">       <span class="attr">xsi:schemaLocation</span>=<span class="string">"</span></div><div class="line">        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</div><div class="line">        http://www.springframework.org/schema/context</div><div class="line">        http://www.springframework.org/schema/context/spring-context.xsd</div><div class="line">        " <span class="attr">default-lazy-init</span>=<span class="string">"true"</span>&gt;</div><div class="line">    <span class="comment">&lt;!--default-lazy-init="true" xml中全部bean延迟加载 --&gt;</span></div><div class="line">    <span class="comment">&lt;!-- lazy-init="false" 表示非延长加载--&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">lazy-init</span>=<span class="string">"false"</span></span></div><div class="line">          <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.dao.impl.AccountDaoImpl"</span>/&gt;</div><div class="line"></div><div class="line">    <span class="comment">&lt;!-- 声明accountService对象,交给spring创建 --&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">"accountService"</span> <span class="attr">class</span>=<span class="string">"com.gtw.spring.springIoc.service.impl.AccountServiceImpl"</span>&gt;</span></div><div class="line">          <span class="comment">&lt;!-- 注入accountDao对象,需要set方法--&gt;</span></div><div class="line">          <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"accountDao"</span> <span class="attr">ref</span>=<span class="string">"accountDao"</span>/&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></div></pre></td></tr></table></figure><p>请务必明确一点，默认情况下Spring容器在启动阶段就会创建bean，这个过程被称为预先bean初始化，这样是有好处的，可尽可能早发现配置错误，如配置文件的出现错别字或者某些bean还没有被定义却被注入等。当然如存在大量bean需要初始化，这可能引起spring容器启动缓慢，一些特定的bean可能只是某些场合需要而没必要在spring容器启动阶段就创建，这样的bean可能是Mybatis的SessionFactory或者Hibernate SessionFactory等，<strong>延迟加载它们会让Spring容器启动更轻松些，从而也减少没必要的内存消耗</strong>。</p><h1 id="＜context-component-scan-＞与＜context-annotation-config-＞"><a href="#＜context-component-scan-＞与＜context-annotation-config-＞" class="headerlink" title="＜context:component-scan/＞与＜context:annotation-config/＞"></a>＜context:component-scan/＞与＜context:annotation-config/＞</h1><p>前面我们使用@Autowired、@Resource、@Value等自动装配注解时用＜context:annotation-config/＞进行注解驱动注册，从而使注解生效。实际上这样＜context:annotation-config/＞一条配置，它的作用是式地向 Spring 容器注册AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及RequiredAnnotationBeanPostProcessor 这 4 个BeanPostProcessor。注册这4个 BeanPostProcessor后Spring容器就能够识别相应的注解了，当然它们也是也可单独配置的。<br>假如想使用@ Resource 、@ PostConstruct、@ PreDestroy等注解就可以单独声明CommonAnnotationBeanPostProcessor<br>如果想使用@PersistenceContext注解，声明PersistenceAnnotationBeanPostProcessor的Bean即可。<br>如果想使用 @Required的注解，就必须声明RequiredAnnotationBeanPostProcessor的Bean。<br>一般来说，这些注解是随处可见的，如果总是需要一条一条配置自然就非常繁琐了，于是spring容器非常智能地为我们提供＜context:annotation-config/＞的简化配置方式，自动声明。<br>对于＜context:component-scan/＞，前面在使用@Service、@Component、@Controller 、@Repository等注解时，需要在xml配置文件声明包扫描驱动＜context:component-scan/＞，它的作用是Spring容器在启动时会启动注解驱动去扫描对应包下的bean对象并将创建它们的实例，这样我们就无法一个个地进行bean配置声明了，极大简化了编程代码。请注意，当spring的xml配置文件出了＜context:component-scan/＞ 后，＜context:annotation-config/＞就可以退休了，因为＜context:component-scan/＞已包含了＜context:annotation-config/＞的功能了。在大部分情况下，都会直接使用＜context:component-scan/＞进行注解驱动注册和包扫描功能。</p><h1 id="IOC-与依赖注入的区别"><a href="#IOC-与依赖注入的区别" class="headerlink" title="IOC 与依赖注入的区别"></a>IOC 与依赖注入的区别</h1><p>IOC:控制反转:将对象的创建权,由Spring管理.<br>DI(依赖注入):在Spring创建对象的过程中,把对象依赖的属性注入到类中。<br>它们两就这样，其他什么毛线都没有了。</p></div><div><div><div style="text-align:center;margin-top:35px;color:#ccc;font-size:14px">------------------------------------本文结束<i class="fa fa-paw"></i>感谢阅读------------------------------------</div></div></div><div><div style="padding:10px 0;margin:20px auto;width:90%;text-align:center"><div>坚持技术分享，你的支持将鼓励我继续创作！</div> <button id="rewardButton" disable="enable" onclick='var qr=document.getElementById("QR");"none"===qr.style.display?qr.style.display="block":qr.style.display="none"'> <span>打赏</span></button><div id="QR" style="display:none"><div id="wechat" style="display:inline-block"> <img id="wechat_qr" src="http://gtw.oss-cn-shanghai.aliyuncs.com/reward.jpg" alt="脱毛大白兔 微信支付"><p>微信支付</p></div></div></div></div><footer class="post-footer"><div class="post-nav"><div class="post-nav-next post-nav-item"><a href="/2017/02/22/SpringFramework结构/" rel="next" title="SpringFramework体系结构及模块包依赖关系"><i class="fa fa-chevron-left"></i> SpringFramework体系结构及模块包依赖关系</a></div><span class="post-nav-divider"></span><div class="post-nav-prev post-nav-item"> <a href="/2017/02/27/Spring AOP/" rel="prev" title="Spring AOP 你不得不知道的事">Spring AOP 你不得不知道的事<i class="fa fa-chevron-right"></i></a></div></div></footer></div></article><div class="post-spread"></div></div></div><div class="comments" id="comments"><div id="gitment-container"></div></div></div><div class="sidebar-toggle"><div class="sidebar-toggle-line-wrap"><span class="sidebar-toggle-line sidebar-toggle-line-first"></span><span class="sidebar-toggle-line sidebar-toggle-line-middle"></span><span class="sidebar-toggle-line sidebar-toggle-line-last"></span></div></div><aside id="sidebar" class="sidebar"><div class="sidebar-inner"><ul class="sidebar-nav motion-element"><li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap"> 文章目录</li><li class="sidebar-nav-overview" data-target="site-overview-wrap"> 站点概览</li></ul><section class="site-overview-wrap sidebar-panel"><div class="site-overview"><div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person"> <img class="site-author-image" itemprop="image" src="http://gtw.oss-cn-shanghai.aliyuncs.com/myself/my3.jpeg?x-oss-process=style/zoom" alt="脱毛大白兔"><p class="site-author-name" itemprop="name">脱毛大白兔</p><p class="site-description motion-element" itemprop="description">一路哼哼唧唧，潇潇洒洒，飘飘扬扬地走下去...</p></div><nav class="site-state motion-element"><div class="site-state-item site-state-posts"> <a href="/archives/"><span class="site-state-item-count">51</span> <span class="site-state-item-name">日志</span></a></div><div class="site-state-item site-state-categories"> <a href="/categories/index.html"><span class="site-state-item-count">9</span> <span class="site-state-item-name">分类</span></a></div><div class="site-state-item site-state-tags"> <a href="/tags/index.html"><span class="site-state-item-count">10</span> <span class="site-state-item-name">标签</span></a></div></nav><div id="music163player" style="margin-bottom:-25px"><iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="2800" height="86" src="//music.163.com/outchain/player?type=2&id=2408566&auto=0&height=66"></iframe></div><div class="links-of-author motion-element"><span class="links-of-author-item"><a href="https://github.com/gaotingwang" target="_blank" title="GitHub"><i class="fa fa-fw fa-github"></i> GitHub</a></span><span class="links-of-author-item"><a href="mailto:code_butcher@sina.com" target="_blank" title="E-Mail"><i class="fa fa-fw fa-envelope"></i> E-Mail</a></span></div><div class="links-of-blogroll motion-element links-of-blogroll-block"><div class="links-of-blogroll-title"><i class="fa fa-fw fa-link"></i> 友情链接</div><ul class="links-of-blogroll-list"><li class="links-of-blogroll-item"> <a href="http://www.ruanyifeng.com/blog/" title="阮一峰日志" target="_blank">阮一峰日志</a></li><li class="links-of-blogroll-item"> <a href="http://blog.didispace.com/" title="程序员DD博客" target="_blank">程序员DD博客</a></li></ul></div></div></section><section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"><div class="post-toc"><div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Spring-IOC-的原理概述"><span class="nav-number">1.</span> <span class="nav-text">Spring IOC 的原理概述</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Spring-容器装配Bean（XML配置方式和注解配置方式）"><span class="nav-number">2.</span> <span class="nav-text">Spring 容器装配Bean（XML配置方式和注解配置方式）</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Spring-依赖注入"><span class="nav-number">3.</span> <span class="nav-text">Spring 依赖注入</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Setter注入"><span class="nav-number">3.1.</span> <span class="nav-text">Setter注入</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#构造函数注入"><span class="nav-number">3.2.</span> <span class="nav-text">构造函数注入</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#循环依赖"><span class="nav-number">3.3.</span> <span class="nav-text">循环依赖</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#自动装配与注解注入"><span class="nav-number">3.4.</span> <span class="nav-text">自动装配与注解注入</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#基于xml的自动装配"><span class="nav-number">3.4.1.</span> <span class="nav-text">基于xml的自动装配</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#基于注解的自动装配-Autowired-amp-Resource-amp-Value"><span class="nav-number">3.4.2.</span> <span class="nav-text">基于注解的自动装配(@Autowired&@Resource&@Value)</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#基于-Autowired注解的自动装配"><span class="nav-number">3.4.2.1.</span> <span class="nav-text">基于@Autowired注解的自动装配</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#基于-Resource注解的自动装配"><span class="nav-number">3.4.2.2.</span> <span class="nav-text">基于@Resource注解的自动装配</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#基于-Value注解的自动装配以及properties文件读取"><span class="nav-number">3.4.2.3.</span> <span class="nav-text">基于@Value注解的自动装配以及properties文件读取</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#IOC容器管理-bean"><span class="nav-number">4.</span> <span class="nav-text">IOC容器管理 bean</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Bean的命名以及实例化方法"><span class="nav-number">4.1.</span> <span class="nav-text">Bean的命名以及实例化方法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Bean的命名"><span class="nav-number">4.1.1.</span> <span class="nav-text">Bean的命名</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Bean实例化方法"><span class="nav-number">4.1.2.</span> <span class="nav-text">Bean实例化方法</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Bean的重写机制"><span class="nav-number">4.2.</span> <span class="nav-text">Bean的重写机制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Bean的作用域"><span class="nav-number">4.3.</span> <span class="nav-text">Bean的作用域</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Singleton作用域"><span class="nav-number">4.3.1.</span> <span class="nav-text">Singleton作用域</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#prototype作用域"><span class="nav-number">4.3.2.</span> <span class="nav-text">prototype作用域</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#request与session作用域"><span class="nav-number">4.3.3.</span> <span class="nav-text">request与session作用域</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#globalSession作用域"><span class="nav-number">4.3.4.</span> <span class="nav-text">globalSession作用域</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Bean的延长加载"><span class="nav-number">4.4.</span> <span class="nav-text">Bean的延长加载</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#＜context-component-scan-＞与＜context-annotation-config-＞"><span class="nav-number">5.</span> <span class="nav-text">＜context:component-scan/＞与＜context:annotation-config/＞</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#IOC-与依赖注入的区别"><span class="nav-number">6.</span> <span class="nav-text">IOC 与依赖注入的区别</span></a></li></ol></div></div></section></div></aside></div></main><footer id="footer" class="footer"><div class="footer-inner"><div class="copyright">&copy; 2015 &mdash; <span itemprop="copyrightYear">2018</span><span class="with-love"><i class="fa fa-user"></i></span> <span class="author" itemprop="copyrightHolder">脱毛大白兔</span></div></div></footer><div class="back-to-top"><i class="fa fa-arrow-up"></i> <span id="scrollpercent"><span>0</span>%</span></div></div><script type="text/javascript">"[object Function]"!==Object.prototype.toString.call(window.Promise)&&(window.Promise=null)</script><script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script><script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script><script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script><script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script><script type="text/javascript" src="/lib/three/three.min.js"></script><script type="text/javascript" src="/lib/three/three-waves.min.js"></script><script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script><link rel="stylesheet" href="https://aimingoo.github.io/gitmint/style/default.css"><script src="https://aimingoo.github.io/gitmint/dist/gitmint.browser.js"></script><style>a.gitment-editor-footer-tip{display:none}.gitment-container.gitment-footer-container{display:none}</style><script type="text/javascript">function renderGitment(){new Gitmint({id:window.location.pathname,owner:"gaotingwang",repo:"blog-comments",lang:"en",oauth:{client_secret:"9e283c98b95c605df85e3c7ab94459861b670c6d",client_id:"0c1815a490b171e0c853"}}).render("gitment-container")}renderGitment()</script><link rel="stylesheet" href="/lib/algolia-instant-search/instantsearch.min.css"><script src="/lib/algolia-instant-search/instantsearch.min.js"></script><script src="/js/src/algolia-search.js?v=5.1.4"></script><script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script><script>AV.initialize("d1eLP5bbeDvg09d922elyLBr-gzGzoHsz","MCTjBqQOcTRrfvljPi77Fzsm")</script><script>function showTime(e){var t=new AV.Query(e),n=[],o=$(".leancloud_visitors");o.each(function(){n.push($(this).attr("id").trim())}),t.containedIn("url",n),t.find().done(function(e){var t=".leancloud-visitors-count";if(0!==e.length){for(var i=0;i<e.length;i++){var s=e[i],r=s.get("url"),l=s.get("time"),c=document.getElementById(r);$(c).find(t).text(l)}for(i=0;i<n.length;i++){r=n[i],c=document.getElementById(r);var u=$(c).find(t);""==u.text()&&u.text(0)}}else o.find(t).text(0)}).fail(function(e,t){console.log("Error: "+t.code+" "+t.message)})}function addCount(e){var t=$(".leancloud_visitors"),n=t.attr("id").trim(),o=t.attr("data-flag-title").trim(),i=new AV.Query(e);i.equalTo("url",n),i.find({success:function(t){if(t.length>0){var i=t[0];i.fetchWhenSave(!0),i.increment("time"),i.save(null,{success:function(e){$(document.getElementById(n)).find(".leancloud-visitors-count").text(e.get("time"))},error:function(e,t){console.log("Failed to save Visitor num, with error message: "+t.message)}})}else{var s=new e,r=new AV.ACL;r.setPublicReadAccess(!0),r.setPublicWriteAccess(!0),s.setACL(r),s.set("title",o),s.set("url",n),s.set("time",1),s.save(null,{success:function(e){$(document.getElementById(n)).find(".leancloud-visitors-count").text(e.get("time"))},error:function(e,t){console.log("Failed to create")}})}},error:function(e){console.log("Error:"+e.code+" "+e.message)}})}$(function(){var e=AV.Object.extend("Counter");1==$(".leancloud_visitors").length?addCount(e):$(".post-title-link").length>1&&showTime(e)})</script><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script><script type="text/x-mathjax-config">
  MathJax.Hub.Config("MathJax config");
</script><script type="text/x-mathjax-config">
  MathJax.Hub.Queue(function() {
    var all = MathJax.Hub.getAllJax(), i;
    for(i=0; i < all.length; i += 1) {
      all[i].SourceElement().parentNode.className += ' has-jax';
    }
  });
</script><script type="text/javascript" src="custom_mathjax_source"></script></body></html>